// Mechanicoder
// 2025年3月10日

#include "model_list.h"
#include "View.h"

#include <QMenu>
#include <QAction>
#include <QHash>

#include <TopoDS_Shape.hxx>
#include <AIS_Shape.hxx>
#include <STEPControl_Writer.hxx>

struct ModelList::Data
{
    Handle(AIS_InteractiveContext) context;
    QMenu* menu = nullptr;

    QHash<QString, Handle(AIS_InteractiveObject)> allPreviewAIS;
};

ModelList::ModelList(QWidget* parent) : QListWidget(parent), _d(std::make_shared<Data>())
{
    connect(this, &QListWidget::itemClicked, this, &ModelList::OnItemClicked);
    connect(this, &QListWidget::customContextMenuRequested, this, &ModelList::OnContextMenu);
    //connect(this, &QListWidget::itemEntered, this, &ModelList::OnItemClicked);

    QAction* action = new QAction("Export STEP", this);
    _d->menu = new QMenu(this);
    _d->menu->addAction(action);
    connect(action, &QAction::triggered, this, &ModelList::OnExport);

    this->setContextMenuPolicy(Qt::CustomContextMenu);
}

ModelList::~ModelList()
{
}

void ModelList::SetupContext(const Handle(AIS_InteractiveContext)& context)
{
    _d->context = context;
}

QColor ToQtColor(int color)
{
    if (color < 0)
    {
        return Qt::black;
    }
    else
    {
        Quantity_Color occ_color = (Quantity_NameOfColor(color));
        QColor qt_color(occ_color.Red(), occ_color.Green(), occ_color.Blue());
        return qt_color;
    }
}

void ModelList::RecordModel(const Handle(AIS_InteractiveObject)& ais, const QString& name, int color/* = -1*/)
{
    if (_d->context && ais)
    {
        if (color >= Quantity_NOC_BLACK && color <= Quantity_NOC_WHITE)
        {
            ais->SetColor(Quantity_NameOfColor(color));
        }

        _d->context->Display(ais, true);

        QListWidgetItem* item = new QListWidgetItem(this);
        SetItemAIS(ais, item);
        item->setText(name);
        item->setForeground(QBrush(ToQtColor(color)));
        this->addItem(item);
        this->setCurrentItem(item);
    }
}

void ModelList::RecordModel(const TopoDS_Shape& shape, const QString& name, int color/* = -1*/)
{
    if (shape.IsNull())
    {
        return;
    }
    Handle(AIS_Shape) ais = new AIS_Shape(shape);
    RecordModel(ais, name, color);
}

// 根据名称更新模型
void ModelList::Preview(const QString& name, const TopoDS_Shape& shape, int color/* = -1*/)
{
    Handle(AIS_Shape) new_ais;
    if (!shape.IsNull())
    {
        new_ais = new AIS_Shape(shape);
        if (color >= Quantity_NOC_BLACK && color <= Quantity_NOC_WHITE)
        {
            new_ais->SetColor(Quantity_NameOfColor(color));
        }

        _d->context->Display(new_ais, false);
    }

    auto it = _d->allPreviewAIS.find(name);
    if (it != _d->allPreviewAIS.end())
    {
        Handle(AIS_InteractiveObject) record_ais = it.value();
        _d->context->Erase(record_ais, false);
    }

    _d->context->UpdateCurrentViewer();
    
    _d->allPreviewAIS[name] = new_ais;
}

void ModelList::Clear()
{
    if (_d->context)
    {
        for (int i = 0; i < this->count(); i++)
        {
            QListWidgetItem* item = this->item(i);
            Handle(AIS_InteractiveObject) ais = GetItemAIS(item);
            if (ais)
            {
                _d->context->Remove(ais, false);
            }
        }

        for (const auto& kv : _d->allPreviewAIS)
        {
            _d->context->Remove(kv, false);
        }
        _d->allPreviewAIS.clear();

        _d->context->UpdateCurrentViewer();
    }
    clear();
}

void ModelList::OnContextMenu(const QPoint& pos)
{
    QListWidgetItem* item = itemAt(pos);
    if (!item)
    {
        qDebug() << "未选择节点";
    }

    _d->menu->exec(this->mapToGlobal(pos));
}

void ModelList::OnExport()
{
    QListWidgetItem* item = currentItem();
    if (!item)
    {
        qDebug() << "未选择节点";
        return;
    }

    Handle(AIS_InteractiveObject) ais = GetItemAIS(item);
    Handle(AIS_Shape) ais_shape = Handle(AIS_Shape)::DownCast(ais);
    if (!ais_shape)
    {
        qDebug() << "节点不存在模型";
        return;
    }

    TopoDS_Shape shape = ais_shape->Shape();
    if (shape.IsNull())
    {
        qDebug() << "节点不存在模型";
        return;
    }

    ExportShape(shape);
}

void ModelList::OnItemClicked(QListWidgetItem* item)
{
    Handle(AIS_InteractiveObject) ais = GetItemAIS(item);
    if (ais && _d->context)
    {
        if (_d->context->IsDisplayed(ais))
        {
            _d->context->Erase(ais, true);
            item->setForeground(QBrush(Qt::gray)); // 隐藏置灰
        }
        else
        {
            _d->context->Display(ais, true);
            _d->context->Activate(ViewHelper::SM_FACE);
            //_d->context->Activate(ViewHelper::SM_WIRE);
            _d->context->Activate(ViewHelper::SM_EDGE);
            item->setForeground(QBrush(Qt::black)); // 显示
        }
    }
}

void ModelList::SetItemAIS(const Handle(AIS_InteractiveObject)& ais, QListWidgetItem* item)
{
    if (item)
    {
        if (ais)
        {
            item->setData(Qt::UserRole, qulonglong(ais.get()));
        }
        else
        {
            item->setData(Qt::UserRole, 0);
        }
    }
}

Handle(AIS_InteractiveObject) ModelList::GetItemAIS(QListWidgetItem* item) const
{
    if (!item)
    {
        return nullptr;
    }
    QVariant raw_data = item->data(Qt::UserRole);
    void* ptr = (void*)raw_data.toULongLong();

    Handle(AIS_InteractiveObject) ais;
    ais.reset((AIS_InteractiveObject*)ptr);
    return ais;
}

void ModelList::ExportShape(const TopoDS_Shape& shape) const
{
    STEPControl_Writer writer;

    writer.Transfer(shape, STEPControl_AsIs);

    const char* filename = "D:/output.stp";
    // 调用Write方法将模型导出到指定文件
    if (writer.Write(filename) != IFSelect_RetDone)
    {
        qDebug() << "Failed to write STEP file: " << filename;
        return;
    }
    qDebug() << "STEP file exported successfully: " << filename;
}
